package cn.jw.starter.swagger;

import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpHeaders;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import cn.jw.starter.common.utils.JwStringUtil;
import cn.jw.starter.swagger.core.JwSwaggerProperties;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import jakarta.annotation.PostConstruct;

/**
 * Swagger starter自动化配置类
 *
 * @author 王广帅
 * @since 2024/4/7 23:16
 */
@AutoConfiguration
@EnableConfigurationProperties(JwSwaggerProperties.class)
public class JwSwaggerAutoConfiguration implements WebMvcConfigurer {

    private Logger logger = LoggerFactory.getLogger(JwSwaggerAutoConfiguration.class);
    @Autowired
    private JwSwaggerProperties swaggerProperties;
    @Autowired
    private ServerProperties serverProperties;

    @PostConstruct
    public void init() {
        if (!swaggerProperties.isEnable()) {
            logger.info("swagger未开启，如果要开启修改配置为true,jw.swagger.enable=true");
        } else {
            int port = serverProperties.getPort();
            logger.info("swagger服务已开启，本地可以访问: http://localhost:{}/swagger-ui/index.html", port);
        }
    }

    @Bean
    @ConditionalOnProperty(value = "jw.swagger.enable", havingValue = "true")
    public OpenAPI createApi(JwSwaggerProperties properties) {
        this.checkSwaggerCoreParam(properties);
        Map<String, SecurityScheme> securitySchemas = buildSecuritySchemes();
        OpenAPI openAPI = new OpenAPI()
            // 接口信息
            .info(buildInfo(properties))
            // 接口安全配置
            .components(new Components().securitySchemes(securitySchemas))
            .addSecurityItem(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION));
        securitySchemas.keySet().forEach(key -> openAPI.addSecurityItem(new SecurityRequirement().addList(key)));
        return openAPI;
    }

    /**
     * 检测swagger配置的核心参数
     * 
     * @param properties
     *            配置类
     */
    private void checkSwaggerCoreParam(JwSwaggerProperties properties) {
        if (JwStringUtil.isBlank(properties.getTitle())) {
            throw new NullPointerException("swagger 标题不能为空");
        }

    }

    /**
     * API 摘要信息
     */
    private Info buildInfo(JwSwaggerProperties properties) {
        return new Info().title(properties.getTitle()).description(properties.getDescription())
            .version(properties.getVersion())
            .contact(new Contact().name(properties.getAuthor()).url(properties.getUrl()).email(properties.getEmail()))
            .license(new License().name(properties.getLicense()).url(properties.getLicenseUrl()));
    }

    /**
     * 安全模式，这里配置通过请求头 Authorization 传递 token 参数
     */
    private Map<String, SecurityScheme> buildSecuritySchemes() {
        Map<String, SecurityScheme> securitySchemes = new HashMap<>();
        SecurityScheme securityScheme = new SecurityScheme().type(SecurityScheme.Type.APIKEY) // 类型
            .name(HttpHeaders.AUTHORIZATION) // 请求头的 name
            .in(SecurityScheme.In.HEADER); // token 所在位置
        securitySchemes.put(HttpHeaders.AUTHORIZATION, securityScheme);
        return securitySchemes;
    }

    // -------------------- 自定义分组接口信息，在不同的系统模块中，可以定义不同的分组，GroupedOpenApi
    // 的bean可以同时存在多个--------------------------------
    /**
     * @Bean public GroupedOpenApi authApi() { return GroupedOpenApi.builder() // 组名
     *       .group("认证接口") // 扫描的路径，支持通配符 .pathsToMatch("/login") // 扫描的包
     *       .packagesToScan("com.demo.controller.auth").build(); }
     * 
     * @Bean public GroupedOpenApi sysApi() { return
     *       GroupedOpenApi.builder().group("系统接口").pathsToMatch("/sys/**").build();
     *       }
     * 
     **/
}
